#------------------------------------------------------------------------------
#*
#*   Copyright 2006 - 2010, Intel Corporation                                                         
#*   All rights reserved. This program and the accompanying materials                          
#*   are licensed and made available under the terms and conditions of the BSD License         
#*   which accompanies this distribution.  The full text of the license may be found at        
#*   http://opensource.org/licenses/bsd-license.php                                            
#*                                                                                             
#*   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
#*   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
#*   
#*    CpuInterrupt.S
#*  
#*   Abstract:
#*
#------------------------------------------------------------------------------

#PUBLIC SystemTimerHandler
#PUBLIC SystemExceptionHandler
#EXTERNDEF mExceptionCodeSize:DWORD

#EXTERN TimerHandler: NEAR
#EXTERN ExceptionHandler: NEAR
#EXTERN mTimerVector: DWORD

#.text
ASM_GLOBAL ASM_PFX(InitDescriptor)

ASM_PFX(InitDescriptor):
        leaq    GDT_BASE(%rip),%rax         # RAX=PHYSICAL address of gdt
        movq    %rax, (gdtr + 2)(%rip)      # Put address of gdt into the gdtr
        lgdt    gdtr(%rip)

        movl    $0x18, %eax
        movl    %eax, %gs
        movl    %eax, %fs

        leaq    IDT_BASE(%rip),%rax         # RAX=PHYSICAL address of idt
        movq    %rax, (idtr + 2)(%rip)      # Put address of idt into the idtr
        lidt    idtr(%rip)
        ret

# VOID
# EFIAPI
# InstallInterruptHandler (
#     UINTN Vector,
#     VOID  (*Handler)(VOID)
#     )
ASM_GLOBAL ASM_PFX(InstallInterruptHandler)
ASM_PFX(InstallInterruptHandler):
#  Vector:DWORD @ 4(%esp)
#  Handler:DWORD @ 8(%esp)
        push     %rbx
        pushfq                              # save eflags
        cli                                 # turn off interrupts
        subq     $0x10, %rsp                # open some space on the stack
        movq     %rsp, %rbx
        
        sidt    (%rbx)                      # get fword address of IDT
        movq    2(%rbx), %rbx               # move offset of IDT into RBX
        addq    $0x10, %rsp                 # correct stack
        movq    %rcx, %rax                  # Get vector number
        shlq    $4, %rax                    # multiply by 16 to get offset
        addq    %rax, %rbx                  # add to IDT base to get entry
        movq    %rdx, %rax                  # load new address into IDT entry
        movw    %ax, (%rbx)                 # write bits 15..0 of offset
        shrq    $16, %rax                   # use ax to copy 31..16 to descriptors
        movw    %ax, 6(%rbx)                # write bits 31..16 of offset
        shrq    $16, %rax                   # use eax to copy 63..32 to descriptors
        movl    %eax, 8(%rbx)               # write bits 63..32 of offset
        popfq                               # restore flags (possible enabling interrupts)
        pop     %rbx
        ret

  .macro JmpCommonIdtEntry
    # jmp     commonIdtEntry - this must be hand coded to keep the assembler from
    #                          using a 8 bit reletive jump when the entries are
    #                          within 255 bytes of the common entry.  This must
    #                          be done to maintain the consistency of the size
    #                          of entry points...
    .byte     0xe9                        # jmp 16 bit reletive 
    .long     commonIdtEntry - . - 4      #  offset to jump to
  .endm

    .p2align 1
ASM_GLOBAL ASM_PFX(SystemExceptionHandler)
ASM_PFX(SystemExceptionHandler):
INT0:
    push     $0x0      # push error code place holder on the stack
    push     $0x0 
    JmpCommonIdtEntry
#    db      0e9h                        # jmp 16 bit reletive 
#    dd      commonIdtEntry - $ - 4      #  offset to jump to
    
INT1:
    push     $0x0      # push error code place holder on the stack
    push     $0x1 
    JmpCommonIdtEntry
    
INT2:
    push     $0x0      # push error code place holder on the stack
    push     $0x2 
    JmpCommonIdtEntry
    
INT3:
    push     $0x0      # push error code place holder on the stack
    push     $0x3 
    JmpCommonIdtEntry
    
INT4:
    push     $0x0      # push error code place holder on the stack
    push     $0x4 
    JmpCommonIdtEntry
    
INT5:
    push     $0x0      # push error code place holder on the stack
    push     $0x5 
    JmpCommonIdtEntry
    
INT6:
    push     $0x0      # push error code place holder on the stack
    push     $0x6 
    JmpCommonIdtEntry
    
INT7:
    push     $0x0      # push error code place holder on the stack
    push     $0x7 
    JmpCommonIdtEntry
    
INT8:
#   Double fault causes an error code to be pushed so no phony push necessary
    nop
    nop
    push     $0x8 
    JmpCommonIdtEntry
    
INT9:
    push     $0x0      # push error code place holder on the stack
    push     $0x9 
    JmpCommonIdtEntry
    
INT10:
#   Invalid TSS causes an error code to be pushed so no phony push necessary
    nop
    nop
    push     $10
    JmpCommonIdtEntry
    
INT11:
#   Segment Not Present causes an error code to be pushed so no phony push necessary
    nop
    nop
    push     $11
    JmpCommonIdtEntry
    
INT12:
#   Stack fault causes an error code to be pushed so no phony push necessary
    nop
    nop
    push    $12
    JmpCommonIdtEntry
    
INT13:
#   GP fault causes an error code to be pushed so no phony push necessary
    nop
    nop
    push     $13
    JmpCommonIdtEntry
    
INT14:
#   Page fault causes an error code to be pushed so no phony push necessary
    nop
    nop
    push     $14
    JmpCommonIdtEntry
    
INT15:
    push     $0x0      # push error code place holder on the stack
    push     $15
    JmpCommonIdtEntry
    
INT16:
    push     $0x0      # push error code place holder on the stack
    push     $16
    JmpCommonIdtEntry
    
INT17:
#   Alignment check causes an error code to be pushed so no phony push necessary
    nop
    nop
    push     $17
    JmpCommonIdtEntry
    
INT18:
    push     $0x0      # push error code place holder on the stack
    push     $18
    JmpCommonIdtEntry
    
INT19:
    push     $0x0      # push error code place holder on the stack
    push     $19
    JmpCommonIdtEntry

INTUnknown:
  # The following segment repeats (32 - 20) times:
  # macro .rept isn't used here because Apple GAS compiler doesn't support it.
  # No. 1
    push     $0x0      # push error code place holder on the stack
    push    $20     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown(%rip) - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 2
    push     $0x0      # push error code place holder on the stack
    push    $21     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown(%rip) - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 3
    push     $0x0      # push error code place holder on the stack
    push    $22     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 4
    push     $0x0      # push error code place holder on the stack
    push    $23     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 5
    push     $0x0      # push error code place holder on the stack
    push    $24     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 6
    push     $0x0      # push error code place holder on the stack
    push    $25     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 7
    push     $0x0      # push error code place holder on the stack
    push    $26     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 8
    push     $0x0      # push error code place holder on the stack
    push    $27     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 9
    push     $0x0      # push error code place holder on the stack
    push    $28     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 10
    push     $0x0      # push error code place holder on the stack
    push    $29     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 11
    push     $0x0      # push error code place holder on the stack
    push    $30     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry
  # No. 12
    push     $0x0      # push error code place holder on the stack
    push    $31     # push vector number
#    .byte    0x6a
#    .byte    ( . - INTUnknown - 3 ) / 9 + 20 # vector number
    JmpCommonIdtEntry


ASM_GLOBAL ASM_PFX(SystemTimerHandler)
ASM_PFX(SystemTimerHandler):
    push     $0
    push     $0  #$ASM_PFX(mTimerVector) //to be patched in Cpu.c
    JmpCommonIdtEntry

commonIdtEntry:
# +---------------------+
# +    EFlags           +
# +---------------------+
# +    CS               +
# +---------------------+
# +    EIP              +
# +---------------------+
# +    Error Code       +
# +---------------------+
# +    Vector Number    +
# +---------------------+
# +    EBP              +
# +---------------------+ <-- EBP

  cli
  push %rbp
  movq %rsp,%rbp

  #
  # Since here the stack pointer is 16-byte aligned, so
  # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
  # is 16-byte aligned
  #       

## UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax#
## UINT64  R8, R9, R10, R11, R12, R13, R14, R15#
  push %r15
  push %r14
  push %r13
  push %r12
  push %r11
  push %r10
  push %r9
  push %r8
  push %rax
  push %rcx
  push %rdx
  push %rbx
  push 6*8(%rbp)
  push (%rbp)
  push %rsi
  push %rdi
  
## UINT64  Gs, Fs, Es, Ds, Cs, Ss#  insure high 16 bits of each is zero
  movzwq  7*8(%rbp), %rax
  push    %rax                      # for ss
  movzwq  4*8(%rbp), %rax
  push    %rax                      # for cs
  movl    %ds, %eax
  push    %rax
  movl    %es, %eax
  push    %rax
  movl    %fs, %eax
  push    %rax
  movl    %gs, %eax
  push    %rax

## UINT64  Rip#
  push    3*8(%rbp)
  
## UINT64  Gdtr[2], Idtr[2]#
  subq    $16, %rsp
  sidt    (%rsp)
  subq    $16, %rsp
  sgdt    (%rsp)
  
## UINT64  Ldtr, Tr#
  xorq    %rax, %rax
  str     %ax
  push    %rax
  sldt    %ax
  push    %rax
  
## UINT64  RFlags#
  push    5*8(%rbp)

## UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8#
  movq    %cr8, %rax
  push    %rax
  movq    %cr4, %rax
  orq     $0x208, %rax
  movq    %rax, %cr4
  push    %rax
  movq    %cr3, %rax
  push    %rax
  movq    %cr2, %rax
  push    %rax
  xorq    %rax, %rax
  push    %rax
  movq    %cr0, %rax
  push    %rax

## UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7#
  movq    %dr7, %rax
  push    %rax

## clear Dr7 while executing debugger itself
  xorq    %rax, %rax
  movq    %rax, %dr7

  movq    %dr6, %rax
  push    %rax
  
## insure all status bits in dr6 are clear...
  xorq    %rax, %rax
  movq    %rax, %dr6

  movq    %dr3, %rax
  push    %rax
  movq    %dr2, %rax
  push    %rax
  movq    %dr1, %rax
  push    %rax
  movq    %dr0, %rax
  push    %rax


## FX_SAVE_STATE_X64 FxSaveState#
  subq $512, %rsp
  movq %rsp, %rdi
  fxsave (%rdi)

## UINT64  ExceptionData#
  push    2*8 (%rbp) 
  
## call into exception handler
## Prepare parameter and call
  movq     1*8(%rbp), %rcx
  movq     %rsp, %rdx
  #
  # Per X64 calling convention, allocate maximum parameter stack space
  # and make sure RSP is 16-byte aligned
  #
  subq    $(4*8+8), %rsp
  cmpq    $32, %rcx
  jb      1f # CallException
  call    ASM_PFX(TimerHandler)
  jmp     2f # ExceptionDone
#CallException:
1:
  call    ASM_PFX(ExceptionHandler)
#ExceptionDone:
2:
  addq    $(4*8+8), %rsp

  cli
## UINT64  ExceptionData#
  addq    $8, %rsp

## FX_SAVE_STATE_X64 FxSaveState#
  movq     %rsp, %rsi
  fxrstor  (%esi)
  addq     $512, %rsp


## UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7#
  pop     %rax
  movq    %rax, %dr0
  pop     %rax
  movq    %rax, %dr1
  pop     %rax
  movq    %rax, %dr2
  pop     %rax
  movq    %rax, %dr3
## skip restore of dr6.  We cleared dr6 during the context save.
  addq    $8, %rsp
  pop     %rax
  movq    %rax, %dr7

## UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8#
  pop     %rax
  movq    %rax, %cr0
  addq    $8, %rsp      # not for Cr1
  pop     %rax
  movq    %rax, %cr2
  pop     %rax
  movq    %rax, %cr3
  pop     %rax
  movq    %rax, %cr4
  pop     %rax
  mov     %rax, %cr8
  
## UINT64  RFlags#
  pop     5*8(%rbp) 

## UINT64  Ldtr, Tr#
## UINT64  Gdtr[2], Idtr[2]#
## Best not let anyone mess with these particular registers...
  addq     $48, %rsp

## UINT64  Rip#
  pop     3*8(%rbp)

## UINT64  Gs, Fs, Es, Ds, Cs, Ss#
  pop     %rax
  # mov     gs, rax # not for gs
  pop     %rax
  # mov     fs, rax # not for fs
  # (X64 will not use fs and gs, so we do not restore it)
  pop     %rax
  movl    %eax, %es    #movq    %rax, %es  #Slice
  pop     %rax
  movl    %eax, %ds
  pop     4*8(%rbp)       # for cs
  pop     7*8(%rbp)       # for ss

## UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax#
## UINT64  R8, R9, R10, R11, R12, R13, R14, R15#
  pop     %rdi
  pop     %rsi
  addq    $8, %rsp                    # not for rbp
  pop     6*8(%rbp)                   # for rsp
  pop     %rbx
  pop     %rdx
  pop     %rcx
  pop     %rax
  pop     %r8
  pop     %r9
  pop     %r10
  pop     %r11
  pop     %r12
  pop     %r13
  pop     %r14
  pop     %r15

  movq    %rbp, %rsp
  pop     %rbp
  addq    $16, %rsp
  iretq


##############################################################################
# data
##############################################################################

  .data

#gdtr: .short GDT_END - GDT_BASE - 1   # GDT limit
gdtr: .short GDT_LEN
        .quad 0  #GDT_BASE                  # (GDT base gets set above)
##############################################################################
#   global descriptor table (GDT)
##############################################################################

        .p2align 4                      # make GDT 16-byte align

GDT_BASE:

# null descriptor
NULL_SEL          = .-GDT_BASE          # Selector [0x0]
        .short 0             # limit 15:0
        .short 0             # base 15:0
        .byte 0              # base 23:16
        .byte 0              # type
        .byte 0              # limit 19:16, flags
        .byte 0              # base 31:24

# linear data segment descriptor
LINEAR_SEL        = .-GDT_BASE          # Selector [0x8]
        .short 0x0FFFF       # limit 0xFFFFF
        .short 0             # base 0
        .byte 0
        .byte 0x092          # present, ring 0, data, expand-up, writable
        .byte 0x0CF          # page-granular, 32-bit
        .byte 0

# linear code segment descriptor
LINEAR_CODE_SEL   = .-GDT_BASE          # Selector [0x10]
        .short 0x0FFFF       # limit 0xFFFFF
        .short 0             # base 0
        .byte 0
        .byte 0x09A          # present, ring 0, code, expand-up, writable
        .byte 0x0CF          # page-granular, 32-bit
        .byte 0

# system data segment descriptor
SYS_DATA_SEL      = .-GDT_BASE          # Selector [0x18]
        .short 0x0FFFF       # limit 0xFFFFF
        .short 0             # base 0
        .byte 0
        .byte 0x092          # present, ring 0, data, expand-up, writable
        .byte 0x0CF          # page-granular, 32-bit
        .byte 0

# system code segment descriptor
SYS_CODE_SEL      = .-GDT_BASE          # Selector [0x20]
        .short 0x0FFFF       # limit 0xFFFFF
        .short 0             # base 0
        .byte 0
        .byte 0x09A          # present, ring 0, code, expand-up, writable
        .byte 0x0CF          # page-granular, 32-bit
        .byte 0

# spare segment descriptor
SPARE3_SEL        = .-GDT_BASE          # Selector [0x28]
        .short 0
        .short 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0

# system data segment descriptor
SYS_DATA64_SEL      = .-GDT_BASE          # Selector [0x30]
        .short 0x0FFFF      # limit 0xFFFFF
        .short 0            # base 0
        .byte 0
        .byte 0x092         # present, ring 0, data, expand-up, writable
        .byte 0x0CF         # page-granular, 32-bit
        .byte 0

# system code segment descriptor
SYS_CODE64_SEL      = .-GDT_BASE          # Selector [0x38]
        .short 0x0FFFF      # limit 0xFFFFF
        .short 0            # base 0
        .byte 0
        .byte 0x09A         # present, ring 0, code, expand-up, writable
        .byte 0x0AF         # page-granular, 64-bit
        .byte 0

# spare segment descriptor
SPARE4_SEL    = .-GDT_BASE            # Selector [0x40]
        .short 0
        .short 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0

GDT_END:
.set GDT_LEN, . - GDT_BASE - 1
 
#idtr: .short IDT_END - IDT_BASE - 1   # IDT limit
idtr: .short IDT_LEN
      .quad 0 #IDT_BASE                  # (IDT base gets set above)
##############################################################################
#   interrupt descriptor table (IDT)
#
#   Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
#       mappings.  This implementation only uses the system timer and all other
#       IRQs will remain masked.  The descriptors for vectors 33+ are provided
#       for convenience.
##############################################################################

        .p2align 3          # make IDT 8-byte align

IDT_BASE:
# divide by zero (INT 0)
DIV_ZERO_SEL        = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# debug exception (INT 1)
DEBUG_EXCEPT_SEL    = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# NMI (INT 2)
NMI_SEL             = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# soft breakpoint (INT 3)
BREAKPOINT_SEL      = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# overflow (INT 4)
OVERFLOW_SEL        = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# bounds check (INT 5)
BOUNDS_CHECK_SEL    = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# invalid opcode (INT 6)
INVALID_OPCODE_SEL  = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# device not available (INT 7)
DEV_NOT_AVAIL_SEL   = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# double fault (INT 8)
DOUBLE_FAULT_SEL    = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# Coprocessor segment overrun - reserved (INT 9)
RSVD_INTR_SEL1      = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# invalid TSS (INT 0ah)
INVALID_TSS_SEL     = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# segment not present (INT 0bh)
SEG_NOT_PRESENT_SEL = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# stack fault (INT 0ch)
STACK_FAULT_SEL     = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# general protection (INT 0dh)
GP_FAULT_SEL        = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# page fault (INT 0eh)
PAGE_FAULT_SEL      = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# Intel reserved - do not use (INT 0fh)
RSVD_INTR_SEL2      = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# floating point error (INT 0x10)
FLT_POINT_ERR_SEL   = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# alignment check (INT 0x11)
ALIGNMENT_CHECK_SEL = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# machine check (INT 0x12)
MACHINE_CHECK_SEL   = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# SIMD floating-point exception (INT 0x13)
SIMD_EXCEPTION_SEL  = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

  # The following segment repeats (32 - 20) times:
  # macro .rept isn't used here because Apple GAS compiler doesn't support it.
  # No. 1
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 2
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 3
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 4
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 5
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 6
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 7
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 8
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 9
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 10
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 11
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved
  # No. 12
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved


# 72 unspecified descriptors
  .fill 72 * 16, 1, 0
        
# IRQ 0 (System timer) - (INT 0x68)
IRQ0_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # 0 for reserved

# IRQ 1 (8042 Keyboard controller) - (INT 0x69)
IRQ1_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
IRQ2_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 3 (COM 2) - (INT 6bh)
IRQ3_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 4 (COM 1) - (INT 6ch)
IRQ4_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 5 (LPT 2) - (INT 6dh)
IRQ5_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 6 (Floppy controller) - (INT 6eh)
IRQ6_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 7 (LPT 1) - (INT 6fh)
IRQ7_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 8 (RTC Alarm) - (INT 0x70)
IRQ8_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 9 - (INT 0x71)
IRQ9_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 10 - (INT 0x72)
IRQ10_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 11 - (INT 0x73)
IRQ11_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 12 (PS/2 mouse) - (INT 0x74)
IRQ12_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 13 (Floating point error) - (INT 0x75)
IRQ13_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 14 (Secondary IDE) - (INT 0x76)
IRQ14_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

# IRQ 15 (Primary IDE) - (INT 0x77)
IRQ15_SEL            = .-IDT_BASE
        .short 0            # offset 15:0
        .short SYS_CODE64_SEL # selector 15:0
        .byte 0             # 0 for interrupt gate
        .byte 0x0e | 0x80   # (10001110)type = 386 interrupt gate, present
        .short 0            # offset 31:16
        .long 0             # offset 63:32
        .long 0             # for reserved

  .fill 16, 1, 0

IDT_END:
  .set IDT_LEN, .-IDT_BASE - 1

#ASM_FUNCTION_REMOVE_IF_UNREFERENCED
